#!/bin/bash

# Description: init fresh mysql server installation
# Authour: zhaodewei

################### options that we need ##########################################################
basedir=''
datadir=''
port=''
innodb_bp_size=''
server_character_set=''
server_as_slave='n'

###################################################################################################
function usage
{
    echo "Usage:"
    echo "    1) $0 -h"
    echo "               show this help info"
    echo "    2) $0 -i"
    echo "               use a step by step interactive guide to init"
    echo "    3) $0 -b basedir -d datadir -p port --innodb-bp-sz xx --default-character-set yyy [--read-only]"
    echo "               basedir: the path where the mysql server binaries exist"
    echo "               datadir: the path where to put data files"
    echo "               innodb-bp-sz: innodb buffer pool size in GB, should be an integer"
    echo "               default-character-set: the default character set of mysql server: latin1 binary gb2312 gbk big5 utf8"
    echo "               read-only: enable the read-only option of mysql server if specified"

    exit 1
}

# read the options
OPTION_PARSE_RES=`getopt -o ihb:d:p: --long innodb-bp-sz:,default-character-set:,read-only -n $0 -- "$@"`
if [ $? -ne 0 ]
then
    usage
fi

eval set -- "$OPTION_PARSE_RES"

case $# in
    2) # -<hi> --
        if [ "$1" == "-h" ]; then
            usage
        elif [ "$1" == "-i" ]; then
            INTERACTIVE_MODE=1
        else
            usage
        fi
    ;;
    11|12) # -b basedir -d datadir -p port --innodb-bp-sz xx --default-character-set yyy [--read-only] --
        while true; do
            case "$1" in
                -b) basedir="$2"; shift 2 ;;
                -d) datadir="$2"; shift 2 ;;
                -p) port="$2"; shift 2 ;;
                --innodb-bp-sz) innodb_bp_size="$2"; shift 2 ;;
                --default-character-set) server_character_set="$2"; shift 2 ;;
                --read-only) server_as_slave='y'; shift ;;
                --) shift; if [ $# -ne 0 ]; then usage; fi; break ;;
                *) usage ;;
            esac
        done
        # assume all requirement options has been set, check this assumption laterly for each corresponding variable
        INTERACTIVE_MODE=0
    ;;
    *)
        usage
    ;;
esac

# **** INTERACTIVE_MODE is 1 or 0, and cann't be changed from here on ***

###################################################################################################
if [ 1 -eq "$INTERACTIVE_MODE" ]; then
    echo "> This script should only be used for fresh mysql server installation.
>
> If the old existing data directory will be used as the datadir, you shouln't
> run this script, instead, you should copy the original confiure file(s)
> to 'etc' subdirectory or generate the congigure file by running scipt 'mysql_gen_cnf'
"

    read -ep "> Continue ? [y/N]: "  continue_or_not
    if [ "$continue_or_not" != 'y' -a "$continue_or_not" != 'Y' ]; then
        exit
    fi

    echo
fi

###################################################################################################
mysql_gen_cnf_options=""

###################################################################################################
{
    if [ 1 -eq "$INTERACTIVE_MODE" ]; then
        default_basedir=$PWD
        read -ep "> specify the mysql server basedir [default: $default_basedir]: " basedir
        if [ -z "$basedir" ]; then
            basedir="$default_basedir"
        else
            basedir=`python -c "import os.path; ab_path=os.path.abspath(os.path.expanduser('${basedir}')); print(ab_path)"`
        fi
    fi

    if [ ! -d "$basedir" ]; then
        echo "---- mysql server basedir '$basedir' NOT exists"
        exit 1
    fi

    # check if the specified basedir is valid
    if [[ ! -x "${basedir}/bin/mysql"  || ! -x "${basedir}/bin/mysqld_safe" ||
        ( ! -x "${basedir}/bin/mysqld" && ! -x "${basedir}/libexec/mysqld" ) ]]
    then
        echo "---- direcctory '$basedir' seems to be an invalid mysql server basedir, check it"
        exit 1
    fi

    mysql_gen_cnf_options="$mysql_gen_cnf_options -b $basedir"

    cd $basedir
}

###################################################################################################
{
    if [ 1 -eq "$INTERACTIVE_MODE" ]; then
        default_datadir="$basedir/var"
        read -ep "> specify the data directory [default: $default_datadir]: " datadir
        if [ -z "$datadir" ]; then
            datadir=$default_datadir
        else # convert to absolute path for safety
            datadir=`python -c "import os.path; ab_path=os.path.abspath(os.path.expanduser('${datadir}')); print(ab_path)"`
        fi
    fi

    datadir_parent_dir_part=`dirname "$datadir"`

    if [ ! -d "$datadir_parent_dir_part" ]; then
        echo "---- parent directory $datadir_parent_dir_part NOT exists"
        exit 1
    fi

    if [ ! -d "$datadir" ]; then # check we can create the datadir
        mkdir "$datadir" 2> /dev/null
        if [ $? -ne 0 ]; then
            echo "---- donn't have permission to create datadir $datadir"
            exit 1
        else
            rmdir $datadir
        fi
    else # $datadir already exists, it must be empty.
        files=`ls "$datadir" 2> /dev/null`
        if [ $? -ne 0 ]; then
            echo "---- $datadir already exist, but have no permission to read it"
            exit 1
        elif [ -n "$files" ]; then
            echo "---- data directory $datadir is NOT empty"
            exit 1
        fi
    fi

    mysql_gen_cnf_options="$mysql_gen_cnf_options -d $datadir"
}

###################################################################################################
while true; do
    if [ 1 -eq "$INTERACTIVE_MODE" ]; then
        default_port=3306
        read -ep "> specify the server port [default: $default_port]: " port
        if [ -z "$port" ]; then
            port=$default_port
        fi
    fi

    if [ "$port" -lt 65536 -a "$port" -gt 0 ]; then
        mysql_gen_cnf_options="$mysql_gen_cnf_options -p $port"
        break
    else
        echo "---- invalid port number: $port"
        if [ 0 -eq "$INTERACTIVE_MODE" ]; then
            exit 1
        fi
    fi
done

###################################################################################################
while true; do
    if [ 1 -eq "$INTERACTIVE_MODE" ]; then
        default_innodb_bp_sz=36
        read -ep "> specify the innodb buffer pool size(GB) [default: $default_innodb_bp_sz]: " innodb_bp_size
        if [ -z "$innodb_bp_size" ]; then
            innodb_bp_size=$default_innodb_bp_sz
        fi
    fi

    if [ "$innodb_bp_size" -gt 0 ]; then
        mysql_gen_cnf_options="$mysql_gen_cnf_options --ibp-sz $innodb_bp_size"
        break
    else
        echo "---- invalid innodb buffer pool size: $innodb_bp_size"
        if [ 0 -eq "$INTERACTIVE_MODE" ]; then
            exit 1
        fi
    fi
done

###################################################################################################
while true; do
    if [ 1 -eq "$INTERACTIVE_MODE" ]; then
        default_character_set="utf8"
        read -ep "> specify the server default character set [default: $default_character_set]: " server_character_set
        if [ -z "$server_character_set" ]; then
            server_character_set=$default_character_set
        fi
    fi

    case "$server_character_set" in
        latin1|binary|gb2312|gbk|big5|utf8 ) mysql_gen_cnf_options="$mysql_gen_cnf_options -c $server_character_set"
                                             break
                                             ;;
        *                                  ) echo -n "---- invalid character set: $server_character_set, "
                                             echo "availiable character sets: latin1 binary gb2312 gbk big5 utf8"
                                             if [ 0 -eq "$INTERACTIVE_MODE" ]; then
                                                 exit 1
                                             fi
                                             ;;
    esac
done

###################################################################################################
while true; do
    if [ 1 -eq "$INTERACTIVE_MODE" ]; then
        read -ep "> specify whether the server will be set as slave (turn read-only ON or OFF) [y/n] [default: n]: " server_as_slave
        if [ -z "$server_as_slave" ]; then
            server_as_slave="n"
        fi
    fi

    server_as_slave=`echo "$server_as_slave" | tr '[:lower:]' '[:upper:]'`
    case "$server_as_slave" in
        Y|YES|1 )  mysql_gen_cnf_options="$mysql_gen_cnf_options --slave"
                   break ;;
        N|NO|0  )  break ;;
        *       )  echo "---- invalid input"
                   if [ 0 -eq "$INTERACTIVE_MODE" ]; then
                       exit 1
                   fi
                   ;;
    esac

done

###################################################################################################
echo


if [ ! -d etc ]; then
    #echo "----> directory 'etc' NOT exists, create it"
    mkdir etc
fi

if [ ! -d log ]; then
    #echo "----> directory 'log' NOT exists, create it"
    mkdir log
fi

if [ ! -d tmp ]; then
    #echo "----> directory 'tmp' NOT exists, create it"
    mkdir tmp
fi


###################################################################################################
echo "----> generate configure file etc/my.cnf"
curr_timestamp=`date "+%Y%m%d%H%M%S"`
mv  etc/my.cnf  etc/my.cnf.bak.$curr_timestamp 2> /dev/null
$basedir/bin/mysql_gen_cnf $mysql_gen_cnf_options > etc/my.cnf 2> /dev/null
if [ $? -ne 0 ]; then
    mysql_gen_cnf $mysql_gen_cnf_options > etc/my.cnf 2> /dev/null
    if [ $? -ne 0 ]; then
        echo "---- failed to generate etc/my.cnf, Hi yanglin05 for help"
        exit 1
    fi
fi

###################################################################################################
if [ -r $basedir/bin/mysql.server ]; then
    MYSQL_SERVER_SCRIPT=$basedir/bin/mysql.server
elif [ -r $basedir/support-files/mysql.server ]; then
    MYSQL_SERVER_SCRIPT=$basedir/support-files/mysql.server
else
    echo "---- mysql.server doesn't exists"
    exit 1
fi

basedir_specified_at_build_phase=`sed -n 's/^# If you install MySQL on some other places than \(.*\), then you$/\1/p' $MYSQL_SERVER_SCRIPT`

if [ "$basedir_specified_at_build_phase" != "$basedir" ]
then
    echo "----> adjust mysql.server"

    # If the mysql server binaries' basedir is different from the basedir specified
    # at the building phase, we must set the @basedir and @datadir variables in
    # mysql.server explicitly so that we can still start/stop/restart mysql server
    # by using mysql.server. Besides, we also set the configure file to
    # @basedir/etc/my.cnf to get the pid-file option
    #
    # re-init is also supported

    sed -i \
        -e "s|^\(basedir=\).*$|\1$basedir|" \
        -e "s|^\(datadir=\).*$|\1$datadir|" \
        -e "s|^\(# check if it's in the\) .* \(and read it from there\)$|\1 'etc' subdirectory \2|" \
        -e "s|datadir/my\.cnf|basedir/etc/my\.cnf|" \
        $MYSQL_SERVER_SCRIPT

    if [ $? -ne 0 ]; then
        echo "---- failed to adjust $MYSQL_SERVER_SCRIPT"
        exit 1
    fi

    # We also need to set the configure file to @basedir/etc/my.cnf in mysqld_safe because
    # my_print_defaults cann't find the configure file automatically in this case.
    #
    # TO avoid redundant change in mysqld_safe when re-init, do a check firstly.
    if ! grep -q 'defaults="--defaults-file=$MY_BASEDIR_VERSION/etc/my.cnf"' $basedir/bin/mysqld_safe
    then
        echo "----> adjust mysqld_safe"

        sed -i '/^if test -z .*MYSQL_HOME/i # default configure file for BaiDu MySQL server \
if test -z "$defaults" -a -r "$MY_BASEDIR_VERSION/etc/my.cnf" \
then \
    defaults="--defaults-file=$MY_BASEDIR_VERSION/etc/my.cnf" \
fi \
'       $basedir/bin/mysqld_safe

        if [ $? -ne 0 ]; then
            echo "---- failed to adjust mysqld_safe"
            exit 1
        fi

    fi

fi

###################################################################################################
echo "----> init mysql server (be patience) ..."
# After MySQL-5.7 use mysqld with --initialize relace mysql_install_db
#./bin/mysql_install_db --defaults-file=etc/my.cnf --keep-my-cnf > /dev/null 2>&1
./libexec/mysqld --defaults-file=etc/my.cnf --initialize > /dev/null 2>&1

if [ $? -ne 0 ]; then
    echo "---- failed to init mysql server"
    exit 1
fi

# Get inited password from mysql.err
password=$(cat log/mysql.err | grep -i 'password is generated' | tail -n 1 | awk '{print $NF}')
if [ x"$password" == x"" ]; then
    echo "---- initialize db failed for generating password failed"
    exit 1
fi
echo "---- init mysql done, temp password is: $password"

###################################################################################################
echo -n "----> "
$MYSQL_SERVER_SCRIPT start

if [ $? -ne 0 ]; then
    echo "---- failed to start mysql server, check the error log for help"
    exit 1
fi

###################################################################################################

echo "----> init root account"
root_pwd=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 19 | head -n 1`
sqls="ALTER USER USER() IDENTIFIED BY'$root_pwd';
      FLUSH PRIVILEGES;
      GRANT ALL ON *.* TO 'root'@'127.0.0.1' IDENTIFIED BY '$root_pwd' WITH GRANT OPTION;
      RESET MASTER;
     "
./bin/mysql -uroot -S tmp/mysql.sock --connect-expired-password -p"$password" -e "$sqls" > /dev/null

cat > etc/user.root.cnf << __EOF__
[client]
user=root
password=$root_pwd
socket=$basedir/tmp/mysql.sock
__EOF__

echo "----> root account info has been written to etc/user.root.cnf"

echo "----> install semi-sync plugins ..."
install_semisync_master="INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'"
install_semisync_slave="INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'"
./bin/mysql -uroot -S tmp/mysql.sock --connect-expired-password -p"$root_pwd" -e "$install_semisync_master ; $install_semisync_slave"

echo "----> Bingo (:"
